home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / net / res_comp.c < prev    next >
C/C++ Source or Header  |  1989-05-18  |  7KB  |  319 lines

  1. /*
  2.  * Copyright (c) 1985 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #if defined(LIBC_SCCS) && !defined(lint)
  14. static char sccsid[] = "@(#)res_comp.c    6.13 (Berkeley) 3/13/88";
  15. #endif /* LIBC_SCCS and not lint */
  16.  
  17. #include <sys/types.h>
  18. #include <stdio.h>
  19. #include <arpa/nameser.h>
  20.  
  21. static int dn_find();
  22.  
  23.  
  24. /*
  25.  * Expand compressed domain name 'comp_dn' to full domain name.
  26.  * 'msg' is a pointer to the begining of the message,
  27.  * 'eomorig' points to the first location after the message,
  28.  * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
  29.  * Return size of compressed name or -1 if there was an error.
  30.  */
  31. int
  32. dn_expand(msg, eomorig, comp_dn, exp_dn, length)
  33.     u_char *msg, *eomorig, *comp_dn, *exp_dn;
  34.     int length;
  35. {
  36.     register u_char *cp, *dn;
  37.     register int n, c;
  38.     u_char *eom;
  39.     int len = -1, checked = 0;
  40.  
  41.     dn = exp_dn;
  42.     cp = comp_dn;
  43.     eom = exp_dn + length - 1;
  44.     /*
  45.      * fetch next label in domain name
  46.      */
  47.     while (n = *cp++) {
  48.         /*
  49.          * Check for indirection
  50.          */
  51.         switch (n & INDIR_MASK) {
  52.         case 0:
  53.             if (dn != exp_dn) {
  54.                 if (dn >= eom)
  55.                     return (-1);
  56.                 *dn++ = '.';
  57.             }
  58.             if (dn+n >= eom)
  59.                 return (-1);
  60.             checked += n + 1;
  61.             while (--n >= 0) {
  62.                 if ((c = *cp++) == '.') {
  63.                     if (dn+n+1 >= eom)
  64.                         return (-1);
  65.                     *dn++ = '\\';
  66.                 }
  67.                 *dn++ = c;
  68.                 if (cp >= eomorig)    /* out of range */
  69.                     return(-1);
  70.             }
  71.             break;
  72.  
  73.         case INDIR_MASK:
  74.             if (len < 0)
  75.                 len = cp - comp_dn + 1;
  76.             cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
  77.             if (cp < msg || cp >= eomorig)    /* out of range */
  78.                 return(-1);
  79.             checked += 2;
  80.             /*
  81.              * Check for loops in the compressed name;
  82.              * if we've looked at the whole message,
  83.              * there must be a loop.
  84.              */
  85.             if (checked >= eomorig - msg)
  86.                 return (-1);
  87.             break;
  88.  
  89.         default:
  90.             return (-1);            /* flag error */
  91.         }
  92.     }
  93.     *dn = '\0';
  94.     if (len < 0)
  95.         len = cp - comp_dn;
  96.     return (len);
  97. }
  98.  
  99. /*
  100.  * Compress domain name 'exp_dn' into 'comp_dn'.
  101.  * Return the size of the compressed name or -1.
  102.  * 'length' is the size of the array pointed to by 'comp_dn'.
  103.  * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
  104.  * is a pointer to the beginning of the message. The list ends with NULL.
  105.  * 'lastdnptr' is a pointer to the end of the arrary pointed to
  106.  * by 'dnptrs'. Side effect is to update the list of pointers for
  107.  * labels inserted into the message as we compress the name.
  108.  * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
  109.  * is NULL, we don't update the list.
  110.  */
  111. int
  112. dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
  113.     u_char *exp_dn, *comp_dn;
  114.     int length;
  115.     u_char **dnptrs, **lastdnptr;
  116. {
  117.     register u_char *cp, *dn;
  118.     register int c, l;
  119.     u_char **cpp, **lpp, *sp, *eob;
  120.     u_char *msg;
  121.  
  122.     dn = exp_dn;
  123.     cp = comp_dn;
  124.     eob = cp + length;
  125.     if (dnptrs != NULL) {
  126.         if ((msg = *dnptrs++) != NULL) {
  127.             for (cpp = dnptrs; *cpp != NULL; cpp++)
  128.                 ;
  129.             lpp = cpp;    /* end of list to search */
  130.         }
  131.     } else
  132.         msg = NULL;
  133.     for (c = *dn++; c != '\0'; ) {
  134.         /* look to see if we can use pointers */
  135.         if (msg != NULL) {
  136.             if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
  137.                 if (cp+1 >= eob)
  138.                     return (-1);
  139.                 *cp++ = (l >> 8) | INDIR_MASK;
  140.                 *cp++ = l % 256;
  141.                 return (cp - comp_dn);
  142.             }
  143.             /* not found, save it */
  144.             if (lastdnptr != NULL && cpp < lastdnptr-1) {
  145.                 *cpp++ = cp;
  146.                 *cpp = NULL;
  147.             }
  148.         }
  149.         sp = cp++;    /* save ptr to length byte */
  150.         do {
  151.             if (c == '.') {
  152.                 c = *dn++;
  153.                 break;
  154.             }
  155.             if (c == '\\') {
  156.                 if ((c = *dn++) == '\0')
  157.                     break;
  158.             }
  159.             if (cp >= eob)
  160.                 return (-1);
  161.             *cp++ = c;
  162.         } while ((c = *dn++) != '\0');
  163.         /* catch trailing '.'s but not '..' */
  164.         if ((l = cp - sp - 1) == 0 && c == '\0') {
  165.             cp--;
  166.             break;
  167.         }
  168.         if (l <= 0 || l > MAXLABEL)
  169.             return (-1);
  170.         *sp = l;
  171.     }
  172.     if (cp >= eob)
  173.         return (-1);
  174.     *cp++ = '\0';
  175.     return (cp - comp_dn);
  176. }
  177.  
  178. /*
  179.  * Skip over a compressed domain name. Return the size or -1.
  180.  */
  181. int
  182. dn_skipname(comp_dn, eom)
  183.     u_char *comp_dn, *eom;
  184. {
  185.     register u_char *cp;
  186.     register int n;
  187.  
  188.     cp = comp_dn;
  189.     while (cp < eom && (n = *cp++)) {
  190.         /*
  191.          * check for indirection
  192.          */
  193.         switch (n & INDIR_MASK) {
  194.         case 0:        /* normal case, n == len */
  195.             cp += n;
  196.             continue;
  197.         default:    /* illegal type */
  198.             return (-1);
  199.         case INDIR_MASK:    /* indirection */
  200.             cp++;
  201.         }
  202.         break;
  203.     }
  204.     return (cp - comp_dn);
  205. }
  206.  
  207. /*
  208.  * Search for expanded name from a list of previously compressed names.
  209.  * Return the offset from msg if found or -1.
  210.  * dnptrs is the pointer to the first name on the list,
  211.  * not the pointer to the start of the message.
  212.  */
  213. static int
  214. dn_find(exp_dn, msg, dnptrs, lastdnptr)
  215.     u_char *exp_dn, *msg;
  216.     u_char **dnptrs, **lastdnptr;
  217. {
  218.     register u_char *dn, *cp, **cpp;
  219.     register int n;
  220.     u_char *sp;
  221.  
  222.     for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
  223.         dn = exp_dn;
  224.         sp = cp = *cpp;
  225.         while (n = *cp++) {
  226.             /*
  227.              * check for indirection
  228.              */
  229.             switch (n & INDIR_MASK) {
  230.             case 0:        /* normal case, n == len */
  231.                 while (--n >= 0) {
  232.                     if (*dn == '\\')
  233.                         dn++;
  234.                     if (*dn++ != *cp++)
  235.                         goto next;
  236.                 }
  237.                 if ((n = *dn++) == '\0' && *cp == '\0')
  238.                     return (sp - msg);
  239.                 if (n == '.')
  240.                     continue;
  241.                 goto next;
  242.  
  243.             default:    /* illegal type */
  244.                 return (-1);
  245.  
  246.             case INDIR_MASK:    /* indirection */
  247.                 cp = msg + (((n & 0x3f) << 8) | *cp);
  248.             }
  249.         }
  250.         if (*dn == '\0')
  251.             return (sp - msg);
  252.     next:    ;
  253.     }
  254.     return (-1);
  255. }
  256.  
  257. /*
  258.  * Routines to insert/extract short/long's. Must account for byte
  259.  * order and non-alignment problems. This code at least has the
  260.  * advantage of being portable.
  261.  *
  262.  * used by sendmail.
  263.  */
  264.  
  265. u_short
  266. _getshort(msgp)
  267.     u_char *msgp;
  268. {
  269.     register u_char *p = (u_char *) msgp;
  270. #ifdef vax
  271.     /*
  272.      * vax compiler doesn't put shorts in registers
  273.      */
  274.     register u_long u;
  275. #else
  276.     register u_short u;
  277. #endif
  278.  
  279.     u = *p++ << 8;
  280.     return ((u_short)(u | *p));
  281. }
  282.  
  283. u_long
  284. _getlong(msgp)
  285.     u_char *msgp;
  286. {
  287.     register u_char *p = (u_char *) msgp;
  288.     register u_long u;
  289.  
  290.     u = *p++; u <<= 8;
  291.     u |= *p++; u <<= 8;
  292.     u |= *p++; u <<= 8;
  293.     return (u | *p);
  294. }
  295.  
  296. void
  297. putshort(s, msgp)
  298.     register u_short s;
  299.     register u_char *msgp;
  300. {
  301.  
  302.     msgp[1] = s;
  303.     msgp[0] = s >> 8;
  304.     return;
  305. }
  306.  
  307. void
  308. putlong(l, msgp)
  309.     register u_long l;
  310.     register u_char *msgp;
  311. {
  312.  
  313.     msgp[3] = l;
  314.     msgp[2] = (l >>= 8);
  315.     msgp[1] = (l >>= 8);
  316.     msgp[0] = l >> 8;
  317.     return;
  318. }
  319.